package com.team.cloudsharing.dao.file;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.team.cloudsharing.dao.folder.FolderDO;
import com.team.cloudsharing.dao.user.UserDO;
import com.team.cloudsharing.ultis.CastArrayList;
import com.team.cloudsharing.ultis.ImageValidate;

@Repository
public class FileDAOImpl implements FileDAO{
	
	final static Logger logger = Logger.getLogger(FileDAOImpl.class);

	@Autowired
	SessionFactory sessionFactory;
	
	
	ImageValidate imageValidate = new ImageValidate();
	
	@Override
	public long insertFile(FileDO fileDO) {
		long fileId = -1;
		Session session = null;
		if (fileDO != null) {
			try {
				session = sessionFactory.openSession();
				Transaction tx = session.beginTransaction();
				session.saveOrUpdate(fileDO);
				tx.commit();
				Serializable id = session.getIdentifier(fileDO);
				fileId = (Long) id;
			} catch (Exception e) {
				logger.error(e.getMessage());
			} finally {
				try {
					session.close();
				} catch (Exception e2) {
					logger.error(e2.getMessage());
				}
			}
		}
		return fileId;
	}

	@Override
	public FileDO findFileById(long fileId) {
		FileDO fileDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			fileDO = (FileDO) session.get(FileDO.class, fileId);
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return fileDO;
	}
	
	@Override
	public FileDO findFileByFileUrl(String fileUrl) {
		FileDO fileDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FileDO.class);
			criteria.add(Restrictions.eq("fileUrl", fileUrl));
			fileDO = (FileDO) criteria.uniqueResult();
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return fileDO;
	}
	
	@Override
	public FileDO findFileByFileNameInFolder(String fileName, FolderDO folderDO) {
		FileDO fileDO = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FileDO.class);
			criteria.add(Restrictions.eq("fileName", fileName));
			criteria.add(Restrictions.eq("folderDO", folderDO));
			fileDO = (FileDO) criteria.uniqueResult();
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return fileDO;
	}

	/*@Override
	public long updateFile(FileDO fileDO) {
		long statusUpdate = -1;
		Session session = null;
		if (fileDO != null) {
			try {
				session = sessionFactory.openSession();
				Query query = session.createQuery("UPDATE FileDO SET file_capacity=:file_capacity, modified_date=:modified_date WHERE file_name=:file_name AND folder_id=:folder_id")
						.setParameter("file_capacity", fileDO.getFileCapacity())
						.setParameter("modified_date", fileDO.getModifiedDate())
						.setParameter("file_name", fileDO.getFileName())
						.setParameter("folder_id", fileDO.getFolderDO().getFolderId());
				query.executeUpdate();
				Serializable id = fileDO.getFileId();
				statusUpdate = (Long) id;
			} catch (Exception e) {
				logger.error(e.getMessage());
			} finally {
				session.close();
			}
		}
		return statusUpdate;
	}*/
	
	@Override
	public long updateFile(FileDO fileDO) {
		return insertFile(fileDO);
//		long statusUpdate = -1;
//		Session session = null;
//		if (fileDO != null) {
//			try {
//				session = sessionFactory.openSession();
//				Transaction tx = session.beginTransaction();
//				session.update(fileDO);
//				tx.commit();
//				Serializable id = session.getIdentifier(fileDO);
//				statusUpdate = (Long) id;
//			} catch (Exception e) {
//				logger.error(e.getMessage());
//			} finally {
//				try {
//					session.close();
//				} catch (Exception e2) {
//					logger.error(e2.getMessage());
//				}
//			}
//		}
//		return statusUpdate;
	}
	
	@Override
	public boolean deleteFile(long fileId) {
		boolean statusDelete = false;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			Query query = session.createQuery("DELETE FROM FileDO WHERE file_id=:file_id")
					.setParameter("file_id", fileId);
			query.executeUpdate();
			statusDelete = true;
		} catch (Exception e) {
			statusDelete = false;
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return statusDelete;
	}

	/*@Override
	public boolean deleteFile(long fileId) {
		boolean statusDelete = false;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			FileDO fileDO = (FileDO) session.load(FileDO.class, fileId);
			Transaction tx = session.getTransaction();
			session.beginTransaction();
			session.delete(fileDO);
			tx.commit();
			statusDelete = true;
		} catch (Exception e) {
			statusDelete = false;
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return statusDelete;
	}*/

	@Override
	public List<FileDO> findAllFileInFolder(FolderDO folderDO, String trashStatus) {
		List<FileDO> listfileDOs = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FileDO.class);
			criteria.add(Restrictions.eq("folderDO", folderDO));
			if (trashStatus.equals("true") || trashStatus.equals("false")){
				boolean isTrash = Boolean.parseBoolean(trashStatus);
				criteria.add(Restrictions.eq("isFileInTrash", isTrash));
			}
			listfileDOs = CastArrayList.castCollection(criteria.list(), FileDO.class);
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listfileDOs;
	}
	
	@Override
	public List<FileDO> findFileByFileNameAndUserId(String fileName, UserDO userDO) {
		Set<FileDO> setFileDOs = new LinkedHashSet<FileDO>();
		List<FileDO> listFileDOs = new ArrayList<FileDO>();
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FileDO.class);
			criteria.add(Restrictions.like("fileName", fileName, MatchMode.ANYWHERE));
			criteria.add(Restrictions.eq("modifiedUserId", userDO.getUserId()));
			criteria.add(Restrictions.eq("isFileInTrash", false));
			setFileDOs.addAll(CastArrayList.castCollection(criteria.list(), FileDO.class));
			listFileDOs.addAll(setFileDOs);
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listFileDOs;
	}


	@Override
	public List<FileDO> findAllImagesInFolder(FolderDO folderDO, String trashStatus,long offset) {
		
		List<FileDO> listImagesDO = null;
		listImagesDO = findAllImagesInFolderLimit(folderDO,offset,trashStatus);
		if(listImagesDO != null){
			listImagesDO = filterImages(listImagesDO);
		}
		return listImagesDO;
		
	}

	

	@SuppressWarnings("unchecked")
	private List<FileDO> findAllImagesInFolderLimit(FolderDO folderDO,long offset, String trashStatus) {
		
		List<FileDO> listImageDOs = null;
		Session session = null;
		boolean isTrash = false;
		List<BigInteger> listFileId = null;
		try{
			session = sessionFactory.openSession();
			//StringBuilder searchQuery = new StringBuilder();
			if (trashStatus.equals("true") || trashStatus.equals("false")){
				isTrash= Boolean.parseBoolean(trashStatus);
			}
			
			String getData = "Select file.file_id from file where folder_id =:folderId and is_file_in_trash =:isTrash order by date_create desc limit :max offset :offset  ";
			SQLQuery query = session.createSQLQuery(getData);
			query.setParameter("folderId", folderDO.getFolderId());
			query.setParameter("isTrash", isTrash);
			query.setParameter("offset", offset);
			query.setParameter("max", 10);
		
			listFileId = query.list();
			listImageDOs = new ArrayList<FileDO>();
			for(BigInteger fileId : listFileId){
				listImageDOs.add(findFileById(fileId.longValue()));
			}
			
			
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return listImageDOs;
	}

	private List<FileDO> filterImages(List<FileDO> listImagesDO) {
		
		List<FileDO> listImagesDOFilter = new ArrayList<FileDO>();
		
		for(FileDO fileDO : listImagesDO){
			if(imageValidate.validate(fileDO.getFileName())){
				listImagesDOFilter.add(fileDO);
			}
			
		}
		
		return listImagesDOFilter;
		
	}

	@Override
	public List<FileDO> findAllFileByFileNamePatternInFolder(String fileNamePattern, FolderDO folderDO) {
		List<FileDO> fileDOs = null;
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(FileDO.class);
			criteria.add(Restrictions.like("fileName", fileNamePattern));
			criteria.add(Restrictions.eq("folderDO", folderDO));
			fileDOs = CastArrayList.castCollection(criteria.list(), FileDO.class);
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				session.close();
			} catch (Exception e2) {
				logger.error(e2.getMessage());
			}
		}
		return fileDOs;
	}

}
